home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / fsattach / fsattach.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-20  |  14.8 KB  |  583 lines

  1. /* 
  2.  * fsattach.c --
  3.  *
  4.  *    Boot-time program to attach all disks to a server.  This
  5.  *    uses a mount file that indicates what prefixes/disks to
  6.  *    attach.  This also siphons off some availability/reliability
  7.  *    information that is put in the summary information sector
  8.  *    on each disk.
  9.  *
  10.  * Copyright 1988 Regents of the University of California
  11.  * Permission to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose and without
  13.  * fee is hereby granted, provided that the above copyright
  14.  * notice appear in all copies.  The University of California
  15.  * makes no representations about the suitability of this
  16.  * software for any purpose.  It is provided "as is" without
  17.  * express or implied warranty.
  18.  */
  19.  
  20. #ifndef lint
  21. static char rcsid[] = "$Header: /sprite/src/admin/fsattach/RCS/fsattach.c,v 1.10 91/01/12 16:48:11 jhh Exp $ SPRITE (Berkeley)";
  22. #endif not lint
  23.  
  24. #include "fsattach.h"
  25.  
  26. char *mountFile = "mount";
  27. char *devDir = "/dev/";
  28. char *fscheck = "fscheck";
  29. int verboseLevel = -1;
  30. Boolean nomount = FALSE;
  31. Boolean sequential = FALSE;
  32. Boolean printOnly = FALSE;
  33. Boolean writeDisk = TRUE;
  34. Boolean fastboot = FALSE;
  35. Boolean debug = FALSE;
  36. int    spriteID = 0;
  37. int    maxChildren = -1;
  38. Boolean condCheck = FALSE;
  39.  
  40. Option optionArray[] = {
  41.     {OPT_STRING,   "d", (char *) &devDir,
  42.     "Device directory."},
  43.     {OPT_STRING,   "fscheck", (char *) &fscheck,
  44.     "fscheck program."},
  45.     {OPT_TRUE,   "f", (char *) &fastboot,
  46.     "Don't check disks."},
  47.     {OPT_INT,   "i", (char *) &spriteID,
  48.     "Preload prefix table with ourself as server of prefixes we export"},
  49.     {OPT_INT,   "j", (char *) &maxChildren,
  50.     "Maximum number of fscheck jobs to run at a time"},
  51.     {OPT_TRUE,   "k", (char *) &debug,
  52.     "Print debugging output."},
  53.     {OPT_STRING,   "m", (char *) &mountFile,
  54.     "File containing disk<=>prefix information."},
  55.     {OPT_TRUE,   "n", (char *) &nomount,
  56.     "No mount."},
  57.     {OPT_TRUE,   "p", (char *) &printOnly,
  58.     "Don't do anything. Just print out actions."},
  59.     {OPT_TRUE,   "s", (char *) &sequential,
  60.     "Ignore group information and run fscheck sequentially."},
  61.     {OPT_TRUE,   "v", (char *) &verbose,
  62.     "Verbose output from fsattach and fscheck."},
  63.     {OPT_FALSE,   "W", (char *) &writeDisk,
  64.     "Don't let fscheck write to the disks."},
  65.     {OPT_TRUE, "c", (char *) &condCheck,
  66.     "Conditionally check the disks (don't re-check)."},
  67.  
  68. };
  69. int numOptions = Opt_Number(optionArray);
  70.  
  71. char        *progName;
  72. int        returnCode;
  73.  
  74. int         mountTableSize = 30;
  75. int        mountTableSizeIncrement = 5;
  76. MountInfo    *mountTable;
  77. int        groupInfoSize = 10;
  78. int        groupInfoSizeIncrement = 2;
  79. GroupInfo    *groupInfo;
  80. int        numGroups;
  81. char        *tempOutputFile = ".fscheck.out";
  82. int        tempOutputFileSize = 8192;
  83. char        *heapLimitString = "1000000";
  84. Boolean        verbose = FALSE;
  85. Boolean     reboot = FALSE;
  86.  
  87.  
  88.  
  89.  
  90. /*
  91.  *----------------------------------------------------------------------
  92.  *
  93.  * main --
  94.  *
  95.  *    Main program for "fsattach":  attach disks at boottime.
  96.  *
  97.  * Results:
  98.  *    None.
  99.  *
  100.  * Side effects:
  101.  *    None.
  102.  *
  103.  *----------------------------------------------------------------------
  104.  */
  105.  
  106. main(argc, argv)
  107.     int argc;
  108.     char *argv[];
  109. {
  110.     int         mountCount = 0;
  111.     int         i;
  112.     int         j;
  113.     ReturnStatus    status;
  114.     int            numChecks;
  115.  
  116.     argc = Opt_Parse(argc, argv, optionArray, numOptions, 0);
  117.  
  118.     returnCode = OK;
  119.     progName = argv[0];
  120.     Alloc(mountTable, MountInfo, mountTableSize, "mountTable");
  121.     assert(mountTable != NULL);
  122.     for (i = 0; i < mountTableSize; i++) {
  123.     mountTable[i].status = CHILD_OK;
  124.     }
  125.     Alloc(groupInfo, GroupInfo, groupInfoSize, "groupInfo");
  126.     assert(groupInfo != NULL);
  127.     bzero(groupInfo, sizeof(GroupInfo) * groupInfoSize);
  128.     strcpy(groupInfo[0].name, "root");
  129.     numGroups = 1;
  130.     status = ParseMount(mountFile, &mountCount);
  131.     if (status != SUCCESS) {
  132.     exit(HARDERROR);
  133.     }
  134.     if (spriteID != 0) {
  135.     PreloadPrefixTable(spriteID, mountCount);
  136.     }
  137.     /*
  138.      * We don't want to check the same partition twice. If two entries in
  139.      * the parse table have the same source then set doCheck on one to
  140.      * false. Also count how many partitions have to be done in each pass.
  141.      */
  142.     numChecks = 0;
  143.     for (i = 0; i < mountCount; i++) {
  144.     for (j = i+1; j < mountCount; j++) {
  145.         if (!strcmp(mountTable[i].source, mountTable[j].source)) {
  146.         mountTable[j].doCheck = FALSE;
  147.         }
  148.     }
  149.     if (mountTable[i].doCheck == TRUE) {
  150.         numChecks++;
  151.     }
  152.     }
  153.     if (!fastboot) {
  154.     CacheWriteBack(FALSE);
  155.     CheckDisks(mountCount, numChecks);
  156.     if (!reboot) {
  157.         CacheWriteBack(TRUE);
  158.     }
  159.     }
  160.     if (reboot) {
  161.     exit(REBOOT);
  162.     }
  163.     if (!nomount) {
  164.     Prefix(mountCount);
  165.     }
  166.     MoveOutput(mountCount);
  167.  
  168.     if (debug) {
  169.     printf("(1) Exiting with %d.\n", returnCode);
  170.     }
  171.     (void) exit(returnCode);
  172. }
  173.  
  174. /*
  175.  *----------------------------------------------------------------------
  176.  *
  177.  * CheckDisks --
  178.  *
  179.  *    Check the disks. For each pass fork of an fscheck process for
  180.  *    each partition to be checked.
  181.  *
  182.  * Results:
  183.  *    FAILURE if an error occurred, SUCCESS otherwise.
  184.  *
  185.  * Side effects:
  186.  *    MountTable entries are modified.
  187.  *
  188.  *----------------------------------------------------------------------
  189.  */
  190.  
  191. ReturnStatus
  192. CheckDisks(mountCount, numChecks)
  193.     int            mountCount;    /* # entries in mount table */
  194.     int            numChecks;    /* # of partitions to check */
  195. {
  196.     int            i;
  197.     ChildInfo        *childInfo;
  198.     int            pass;
  199.     int            doneChildren;
  200.     int            activeChildren;
  201.     union wait         waitStatus;
  202.     ReturnStatus    status;
  203.     int            childPid;
  204.     MountInfo        *mountPtr;
  205.  
  206.     Alloc(childInfo, ChildInfo, numChecks, "childInfo");
  207.     assert(childInfo != NULL);
  208.     for (i = 0; i < numChecks; i++) {
  209.     childInfo[i].pid = -1;
  210.     }
  211.     activeChildren = 0;
  212.     doneChildren = 0;
  213.     if (maxChildren < 0) {
  214.     maxChildren = numGroups;
  215.     }
  216.     while (doneChildren < numChecks) {
  217.     while (activeChildren < maxChildren) {
  218.         status = RunChild(mountCount, numChecks, childInfo, &i);
  219.         if (status == FAILURE) {
  220.         if (i < 0) {
  221.             /*
  222.              * There are no available jobs that can be run.
  223.              * Wait for some to finish.
  224.              */
  225.             assert(activeChildren > 0);
  226.             break;
  227.         }
  228.         /*
  229.          * Some sort of error occurred.
  230.          */
  231.         mountTable[i].doCheck = FALSE;
  232.         returnCode = HARDERROR;
  233.         doneChildren++;
  234.         } else {
  235.         mountTable[i].status = CHILD_RUNNING;
  236.         groupInfo[mountTable[i].group].running = TRUE;
  237.         activeChildren++;
  238.         if (sequential) {
  239.             break;
  240.         }
  241.         }
  242.     }
  243.     if (activeChildren > 0) {
  244.         if (printOnly) {
  245.         for (i = 0; i < mountCount; i++) {
  246.             if (mountTable[i].status == CHILD_RUNNING) {
  247.             break;
  248.             }
  249.         }
  250.         assert(i != numChecks);
  251.         childPid = i;
  252.         } else {
  253.         childPid = wait(&waitStatus);
  254.         }
  255.         activeChildren--;
  256.         for (i = 0; i < numChecks; i++) {
  257.         if (childInfo[i].pid == childPid) {
  258.             mountPtr = &(mountTable[childInfo[i].mountIndex]);
  259.             childInfo[i].pid = -1;
  260.             break;
  261.         }
  262.         }
  263.         if (verbose) {
  264.         printf("Fscheck of %s finished.\n", mountPtr->source);
  265.         }
  266.         if (printOnly) {
  267.         doneChildren++;
  268.         mountPtr->status = CHILD_OK;
  269.         mountPtr->doCheck = FALSE;
  270.         groupInfo[mountPtr->group].running = FALSE;
  271.         continue;
  272.         }
  273.         if (WIFEXITED(waitStatus) && 
  274.         waitStatus.w_retcode == FSCHECK_OUT_OF_MEMORY) {
  275.         continue;
  276.         }
  277.         doneChildren++;
  278.         mountPtr->doCheck = FALSE;
  279.         mountPtr->checked = TRUE;
  280.         groupInfo[mountPtr->group].running = FALSE;
  281.         if (WIFSIGNALED(waitStatus) || WIFSTOPPED(waitStatus)) {
  282.         (void) fprintf(stderr,"%s did not finish.\n", fscheck);
  283.         returnCode = HARDERROR;
  284.         mountPtr->status = CHILD_FAILURE;
  285.         } else if (waitStatus.w_retcode == EXEC_FAILED) {
  286.         returnCode = HARDERROR;
  287.         mountPtr->status = CHILD_FAILURE;
  288.         } else {
  289.         if (debug) {
  290.             printf("%s returned 0x%x.\n", fscheck,
  291.             (unsigned int) waitStatus.w_retcode);
  292.             printf("returnCode is %d.\n", returnCode);
  293.         }
  294.         mountPtr->status = CHILD_OK;
  295.         if ((char) waitStatus.w_retcode < 0 ) {
  296.             PrintFscheckError((char)waitStatus.w_retcode, mountPtr);
  297.             mountPtr->status = CHILD_FAILURE;
  298.             returnCode = HARDERROR;
  299.         } else if ((char) waitStatus.w_retcode > 0) {
  300.             PrintFscheckError((char)waitStatus.w_retcode, mountPtr);
  301.             if ((char) waitStatus.w_retcode == FSCHECK_REBOOT) {
  302.             reboot = TRUE;
  303.             }
  304.             if (returnCode == OK) {
  305.             returnCode = SOFTERROR;
  306.             }
  307.         } else if (verbose) {
  308.             PrintFscheckError((char)waitStatus.w_retcode, mountPtr);
  309.         }
  310.         }
  311.     }
  312.     }
  313.     assert(doneChildren == numChecks);
  314.     assert(activeChildren == 0);
  315. }
  316.  
  317. /*
  318.  *----------------------------------------------------------------------
  319.  *
  320.  * CacheWriteBack --
  321.  *
  322.  *    Turns cache write-back on and off
  323.  * Results:
  324.  *    None.
  325.  *
  326.  * Side effects:
  327.  *    The cache write-back status is changed.
  328.  *
  329.  *----------------------------------------------------------------------
  330.  */
  331.  
  332. void
  333. CacheWriteBack(value)
  334.     int        value;
  335. {
  336.  
  337.     int            newValue;
  338.     ReturnStatus    status;
  339.     int            lockedBlocks;
  340.  
  341.     if (printOnly && verbose) {
  342.     printf("Setting cache write-back to %d.\n", value);
  343.     return;
  344.     }
  345.     if (!writeDisk) {
  346.     if (verbose) {
  347.         fprintf(stderr, 
  348.             "Fscheck not writing disks -- not changing  write-back.\n");
  349.     }
  350.     return;
  351.     }
  352.     newValue = value;
  353.     status = Fs_Command(FS_DISABLE_FLUSH, sizeof(int), (Address) &value);
  354.     if (status != SUCCESS) {
  355.     (void) fprintf(stderr, "Fs_Command (1)  returned %d.\n", status);
  356.     (void) exit(HARDERROR);
  357.     }
  358.     if (verbose) {
  359.     (void) fprintf(stderr, "Cache write-back %s, was %s.\n", 
  360.         (newValue) ? "on" : "off",
  361.             (value) ? "on" : "off");
  362.     }
  363.     /*
  364.      * If we're turning the write-back off flush what's in the cache already.
  365.      */
  366.     if (newValue == 0) {
  367.     status = Fs_Command(FS_EMPTY_CACHE, sizeof(int), 
  368.             (Address) &lockedBlocks);
  369.     if (status != SUCCESS) {
  370.         (void) fprintf(stderr, "Fs_Command (2)  returned %d.\n", status);
  371.         (void) exit(HARDERROR);
  372.     }
  373.     if (lockedBlocks > 0) {
  374.         fprintf(stderr, "There are %d locked blocks in the cache ?!\n", 
  375.         lockedBlocks);
  376.     }
  377.     }
  378. }
  379.  
  380. /*
  381.  *----------------------------------------------------------------------
  382.  *
  383.  * RunChild --
  384.  *
  385.  *    Forks a process to run fscheck.
  386.  *
  387.  * Results:
  388.  *    None.
  389.  *
  390.  * Side effects:
  391.  *    A process is forked.
  392.  *
  393.  *----------------------------------------------------------------------
  394.  */
  395.  
  396. ReturnStatus
  397. RunChild(mountCount, numChecks, childInfo, mountIndexPtr)
  398.     int        mountCount;        /* # entries in mount table */
  399.     int        numChecks;        /* # of jobs to run */
  400.     ChildInfo    *childInfo;        /* info on running children */
  401.     int        *mountIndexPtr;        /* ptr to index into mount table */
  402. {
  403.     int        mountIndex;
  404.     int        i;
  405.     MountInfo    *mountPtr = NULL;
  406.     static char    deviceName[MAX_FIELD_LENGTH];
  407.     static char    partition[MAX_FIELD_LENGTH];
  408.     static char    outputFile[MAX_FIELD_LENGTH];
  409.     int        pid;
  410.     ArgHeader    *argPtr;
  411.     Boolean    defaultOutputFile = TRUE;
  412.     Boolean    defaultRootPart = TRUE;
  413.     Boolean    defaultDir = TRUE;
  414.  
  415.     /*
  416.      * Find a child to run.
  417.      */
  418.     *mountIndexPtr = -1;
  419.     for (mountIndex = 0; mountIndex < mountCount; mountIndex++) {
  420.     if (mountTable[mountIndex].group == 0 &&
  421.         mountTable[mountIndex].status == CHILD_RUNNING) {
  422.         break;
  423.     }
  424.     if ((mountTable[mountIndex].doCheck) &&
  425.         (groupInfo[mountTable[mountIndex].group].running == FALSE) &&
  426.         (mountTable[mountIndex].status != CHILD_RUNNING)) {
  427.         mountPtr = &(mountTable[mountIndex]);
  428.         break;
  429.     }
  430.     }
  431.     if (mountPtr == NULL) {
  432.     return FAILURE;
  433.     }
  434.     *mountIndexPtr = mountIndex;
  435.     /*
  436.      * Put together the arguments to fscheck.
  437.      */
  438.     (void) strcpy(partition, &(mountPtr->source[strlen(mountPtr->source) -1 ]));
  439.     (void) strcpy(deviceName, mountPtr->source);
  440.     deviceName[strlen(mountPtr->source) - 1] = '\0';
  441.     StartExec(fscheck, fscheck);
  442.     AddExecArgs("-dev", deviceName, NULL);
  443.     AddExecArgs("-part", partition, NULL);
  444.     LIST_FORALL((List_Links *) &mountPtr->argInfo.argList, 
  445.     (List_Links *) argPtr) {
  446.     if (!strcmp("-verbose", argPtr->arg) && verbose) {
  447.         continue;
  448.     } else if (!strcmp(argPtr->arg, "-write") && !writeDisk) {
  449.         continue;
  450.     } else if (!strcmp("-dir", argPtr->arg)) {
  451.         defaultDir = FALSE;
  452.     }
  453.     AddExecArgs(argPtr->arg, NULL);
  454.     }
  455.     DeleteList(&mountPtr->argInfo.argList);
  456.     if (verbose) {
  457.     AddExecArgs("-verbose", NULL);
  458.     }
  459.     if (writeDisk) {
  460.     AddExecArgs("-write", NULL);
  461.     }
  462.     AddExecArgs("-outputFile", tempOutputFile, NULL);
  463.     AddExecArgs("-rawOutput", NULL);
  464.     if (condCheck) {
  465.     AddExecArgs("-cond", "-setCheck", NULL);
  466.     }
  467.     if (defaultDir) {
  468.     AddExecArgs("-dir", devDir, NULL);
  469.     }
  470.     pid = DoExec();
  471.     if (pid < 0) {
  472.     if (verbose) {
  473.         fprintf(stderr, "Fork of child failed.\n");
  474.         perror("");
  475.     }
  476.     return FAILURE;
  477.     }
  478.     /*
  479.      * Store info about the running child.
  480.      */
  481.     for (i = 0; i < numChecks; i++) {
  482.     if (childInfo[i].pid == -1) {
  483.         if (printOnly) {
  484.         childInfo[i].pid = mountIndex;
  485.         } else {
  486.         childInfo[i].pid = pid;
  487.         }
  488.         childInfo[i].mountIndex = mountIndex;
  489.         break;
  490.     }
  491.     }
  492.     assert(i != numChecks);
  493.     return SUCCESS;
  494. }
  495.  
  496. /*
  497.  *----------------------------------------------------------------------
  498.  *
  499.  * Prefix --
  500.  *
  501.  *    Adds all devices that were checked correctly to the prefix table.
  502.  *
  503.  * Results:
  504.  *    None.
  505.  *
  506.  * Side effects:
  507.  *    Entries are added to the system prefix table.
  508.  *
  509.  *----------------------------------------------------------------------
  510.  */
  511.  
  512. void
  513. Prefix(count)
  514.     int        count;        /* # entries in mount table */
  515. {
  516.     int            i;
  517.     ReturnStatus    status;
  518.     int            flags;
  519.     Fs_TwoPaths        paths;
  520.     char        buffer[128];
  521.     char        *source;
  522.     char        *dest;
  523.     Boolean        device;
  524.     char        *prefix;
  525.  
  526.     for (i = 0; i < count; i ++) {
  527.     if (mountTable[i].status == CHILD_OK) {
  528.         flags = 0;
  529.         if (mountTable[i].readonly) {
  530.         flags |= FS_ATTACH_READ_ONLY;
  531.         }
  532.         if (mountTable[i].export == FALSE) {
  533.         flags |= FS_ATTACH_LOCAL;
  534.         }
  535.         source = mountTable[i].source;
  536.         dest = mountTable[i].dest;
  537.         device = mountTable[i].device;
  538.         /*
  539.          * Use Fs_AttachDisk to attach a disk.
  540.          */
  541.         if (device == TRUE) {
  542.         printf("Attaching %s%s as %s.\n", devDir, source, dest);
  543.         printf("%s %s.\n", mountTable[i].readonly ? "R" : "RW",
  544.                mountTable[i].export ? "Export" : "Local");
  545.         if (printOnly) {
  546.             continue;
  547.         }
  548.         sprintf(buffer, "%s%s", devDir, source);
  549.  
  550.         status = Fs_AttachDisk(buffer, dest, flags);
  551.         if (status == FS_DOMAIN_UNAVAILABLE) {
  552.             printf("%s is already attached.\n", buffer);
  553.             prefix = GetAttachName(buffer);
  554.             if (prefix != NULL) {
  555.             source = prefix;
  556.             device = FALSE;
  557.             }
  558.         } else if (status != SUCCESS) {
  559.             (void) fprintf(stderr, "Attach \"%s\" on \"%s\": %s\n", 
  560.                 buffer, dest, Stat_GetMsg(status));
  561.         }
  562.         }
  563.         if (device == FALSE) {
  564.         printf("Exporting %s as %s.\n", source, dest);
  565.         if (printOnly) {
  566.             continue;
  567.         }
  568.         paths.pathLen1 = strlen(source) +1;
  569.         paths.path1 = source;
  570.         paths.pathLen2 = strlen(dest) +1;
  571.         paths.path2 = dest;
  572.         status = Fs_Command(FS_PREFIX_EXPORT, sizeof(paths), 
  573.                         (Address) &paths);
  574.         if (status != SUCCESS) {
  575.             fprintf(stderr, 
  576.                 "Couldn't export  \"%s\" as \"%s\": %s\n",
  577.                 source, dest, Stat_GetMsg(status));
  578.         }
  579.         }
  580.     }
  581.     }
  582. }
  583.